library(sp)
library(spdep)
library(dplyr)
library(rstan)
library(loo)
library(ggplot2)
library(bayesplot)
library(glmnet)
Error in library(glmnet) : there is no package called ‘glmnet’
GM@data <- GM@data %>%
mutate(
log_pm25 = log(pm25),
log_sat = log(sat_2014)
)
What variables are available in this data set?
print(colnames(GM@data))
[1] "City_locality" "iso3" "country"
[4] "super_region" "super_region_name" "pm25"
[7] "sat_2014" "log_pm25" "log_sat"
Regression on the original values instead of in log-domain
xylabs <- labs(
x = expression(satellite),
y = expression(PM[2.5])
)
region_color_manual = scale_color_manual(
values =
c("E-Eur/C-Eur/C-Asia" = "#00C094",
"HighIncome" = "#FB61D7",
"LatAm/Carib" = "#53B400",
"N-Afr/MidEast" = "#A58AFF",
"S-Asia" = "#00B6EB",
"SE-Asia/E-Asia/Oceania" = "#C49A00",
"Sub-Saharan Afr" = "#F8766D")
)
plot1 <- ggplot(GM@data, aes(y = pm25, x = sat_2014)) +
geom_point(aes(color = super_region_name), alpha = 0.4, size = rel(0.8)) +
region_color_manual +
geom_smooth(method = lm, color = "black", size = 0.5, linetype = 2) +
coord_equal() +
xylabs +
guides(color = guide_legend(
title = NULL,
override.aes = list(alpha = 1, size = 2)
)) +
theme(legend.text = element_text(size = rel(0.6)))
plot(plot1)

Fitting a second degree polynomial instead
xylabs <- labs(
x = expression(log(satellite)),
y = expression(log(PM[2.5]))
)
region_color_manual = scale_color_manual(
values =
c("E-Eur/C-Eur/C-Asia" = "#00C094",
"HighIncome" = "#FB61D7",
"LatAm/Carib" = "#53B400",
"N-Afr/MidEast" = "#A58AFF",
"S-Asia" = "#00B6EB",
"SE-Asia/E-Asia/Oceania" = "#C49A00",
"Sub-Saharan Afr" = "#F8766D")
)
plot1 <- ggplot(GM@data, aes(y = log_pm25, x = log_sat)) +
geom_point(aes(color = super_region_name), alpha = 0.4, size = rel(0.8)) +
region_color_manual +
geom_smooth(method = glm, formula=y~poly(x, 2), color = "black", size = 0.5, linetype = 2) +
coord_equal() +
xylabs +
guides(color = guide_legend(
title = NULL,
override.aes = list(alpha = 1, size = 2)
)) +
theme(legend.text = element_text(size = rel(0.6)))
plot(plot1)

Model used in the paper
xylabs <- labs(
x = expression(log(satellite)),
y = expression(log(PM[2.5]))
)
region_color_manual = scale_color_manual(
values =
c("E-Eur/C-Eur/C-Asia" = "#00C094",
"HighIncome" = "#FB61D7",
"LatAm/Carib" = "#53B400",
"N-Afr/MidEast" = "#A58AFF",
"S-Asia" = "#00B6EB",
"SE-Asia/E-Asia/Oceania" = "#C49A00",
"Sub-Saharan Afr" = "#F8766D")
)
plot1 <- ggplot(GM@data, aes(y = log_pm25, x = log_sat)) +
geom_point(aes(color = super_region_name), alpha = 0.4, size = rel(0.8)) +
region_color_manual +
geom_smooth(method = lm, color = "black", size = 0.5, linetype = 2) +
coord_equal() +
xylabs +
guides(color = guide_legend(
title = NULL,
override.aes = list(alpha = 1, size = 2)
)) +
theme(legend.text = element_text(size = rel(0.6)))
plot(plot1)

r1 <- subset(GM@data, super_region==1)
r2 <- subset(GM@data, super_region==2)
r3 <- subset(GM@data, super_region==3)
r4 <- subset(GM@data, super_region==4)
r5 <- subset(GM@data, super_region==5)
r6 <- subset(GM@data, super_region==6)
r7 <- subset(GM@data, super_region==7)
b1 <- lm(r1$log_pm25 ~ r1$log_sat)
print(b1$coefficients)
(Intercept) r1$log_sat
1.2928677 0.4628297
b2 <- lm(r2$log_pm25 ~ r2$log_sat)
print(b2$coefficients)
(Intercept) r2$log_sat
1.424214 0.700595
b3 <- lm(r3$log_pm25 ~ r3$log_sat)
print(b3$coefficients)
(Intercept) r3$log_sat
0.4585961 0.9131791
b4 <- lm(r4$log_pm25 ~ r4$log_sat)
print(b4$coefficients)
(Intercept) r4$log_sat
1.0401566 0.6807239
b5 <- lm(r5$log_pm25 ~ r5$log_sat)
print(b5$coefficients)
(Intercept) r5$log_sat
2.3130627 0.2960964
b6 <- lm(r6$log_pm25 ~ r6$log_sat)
print(b6$coefficients)
(Intercept) r6$log_sat
1.8787025 0.5071027
b7 <- lm(r7$log_pm25 ~ r7$log_sat)
print(b7$coefficients)
(Intercept) r7$log_sat
2.9589930 0.1482167
plot_r1 <- ggplot(r3, aes(y = log_pm25, x = log_sat)) +
geom_point(aes(colour = super_region_name), alpha = 0.2, size = rel(0.75)) +
region_color_manual +
geom_smooth(aes(colour = super_region_name), method = lm) +
coord_equal() +
xylabs +
legend_none()
plot(plot_r1)

Same plot as above + separate fits for each super-region
plot2 <- ggplot(GM@data, aes(y = log_pm25, x = log_sat)) +
geom_point(aes(colour = super_region_name), alpha = 0.2, size = rel(0.75)) +
geom_smooth(method = lm, color = "black", size = 0.5, linetype = 2) +
region_color_manual +
geom_smooth(aes(colour = super_region_name), method = lm) +
coord_equal() +
xylabs +
legend_none()
plot(plot2)

Derive labels from the data based on average PM2.5 concentration in each country
average <-
GM@data %>%
group_by(iso3) %>%
summarise(pm25 = mean(pm25))
d <- dist(average)
NAs introduced by coercion
hh <- hclust(d)
clust <- cutree(hh,k = 6)
GM@data$cluster_region <-
sapply(GM@data$iso3, function(x) clust[which(average$iso3 == x)])
print(table(GM@data$cluster_region))
1 2 3 4 5 6
14 2172 400 376 10 8
cluster_color_manual = scale_color_manual(
values =
c("4" = "#00C094",
"1" = "#FB61D7",
"5" = "#53B400",
"2" = "#A58AFF",
"3" = "#00B6EB",
"6" = "#C49A00",
"7" = "#F8766D")
)
plot3 <-
ggplot(GM@data, aes(
y = log_pm25,
x = log_sat
)) +
geom_point(aes(colour = as.factor(cluster_region)), alpha = 0.2, size = rel(0.75)) +
cluster_color_manual +
geom_smooth(
method = lm,
color = "black",
size = 0.5,
linetype = 2
) +
geom_smooth(aes(colour = as.factor(cluster_region)), method = lm) +
coord_equal() +
guides(color = guide_legend(
title = NULL,
override.aes = list(alpha = 1, size = 2)
)) +
xylabs
plot(plot3)
# Prior predictive simulations --------------------------------------------
# Inverse Gamme distribution.
library(gridExtra)
library(grid)
library(invgamma)
library(ggplot2); theme_set(theme_bw())
x <- seq(0, 500, .01)
qplot(x, dinvgamma(x, 1, 1), geom = "line") -> plot1
qplot(x, dinvgamma(x, 1, 100), geom = "line") -> plot2
#qplot(x, 1/dinvgamma(x, 1, 1), geom = "line") -> plot3
#qplot(x, 1/dinvgamma(x, 1, 100), geom = "line") -> plot4
#qplot(x, dinvgamma(x, 2, 100), geom = "line") -> plot3
#qplot(x, dinvgamma(x, 4, 100), geom = "line") -> plot4
grid.arrange(plot1, plot2, ncol = 2)

# Plot: prior predictive with vague priors
set.seed(seed = 1923840483)
tau0 <- 1 / sqrt(rgamma(1, 1, rate = 100))
tau1 <- 1 / sqrt(rgamma(1, 1, rate = 100))
sigma <- 1 / sqrt(rgamma(1, 1, rate = 100))
beta0i <- rnorm(8, 0, tau0)
beta1i <- rnorm(8, 0, tau1)
beta0 <- rnorm(1, 0, 100)
beta1 <- rnorm(1, 0, 100)
Nsim <- length(GM@data$super_region)
xysim_labs <- labs(
x = expression(paste("Observed ", log(PM[2.5]))),
y = "Simulated data (log scale)"
)
data1 <- data.frame(
log_pm25 = GM$log_pm25,
sim = beta0 + beta0i[GM$super_region] +
(beta1 + beta1i[GM$super_region]) * GM$log_sat +
rnorm(Nsim, mean = 0, sd = sigma)
)
theme_set(bayesplot::theme_default(base_size = 18))
theme_update(axis.text = element_text(size = 20))
ggplot(data1, aes(x = log_pm25, y = sim)) +
geom_point(alpha = 0.1, color = "red") +
xysim_labs + ggtitle("Vague Recommended Priors")
ggsave(filename = "plots/prior_pred_vague.png", width = 4.5, height = 3.75)

# Plot: prior predictive with weakly informative priors
set.seed(seed = 1923840479)
tau0 <- abs(rnorm(1, 0, 1))
tau1 <- abs(rnorm(1, 0, 1))
sigma <- abs(rnorm(1, 0, 1))
beta0i <- rnorm(8, 0, tau0)
beta1i <- rnorm(8, 0, tau1)
beta0 <- rnorm(1, 0, 1)
beta1 <- rnorm(1, 1, 1)
data2 <- data.frame(
log_pm25 = GM$log_pm25,
sim = beta0 + beta0i[GM$super_region] +
(beta1 + beta1i[GM$super_region]) * GM$log_sat +
rnorm(Nsim, mean = 0, sd = sigma)
)
ggplot(data2, aes(x = log_pm25, y = sim)) +
geom_point(alpha = 0.1) +
xysim_labs + ggtitle("Weakly informative joint prior data generating process")
ggsave(filename = "plots/prior_pred_wip.png", width = 4.5, height = 3.75)

# Plot: prior predictive with weakly informative priors (no seed)
tau0 <- abs(rnorm(1, 0, 1))
tau1 <- abs(rnorm(1, 0, 1))
sigma <- abs(rnorm(1, 0, 1))
beta0i <- rnorm(8, 0, tau0)
beta1i <- rnorm(8, 0, tau1)
beta0 <- rnorm(1, 0, 1)
beta1 <- rnorm(1, 1, 1)
data2 <- data.frame(
log_pm25 = GM$log_pm25,
sim = beta0 + beta0i[GM$super_region] +
(beta1 + beta1i[GM$super_region]) * GM$log_sat +
rnorm(Nsim, mean = 0, sd = sigma)
)
ggplot(data2, aes(x = log_pm25, y = sim)) +
geom_point(alpha = 0.1) +
xysim_labs
ggsave(filename = "plots/prior_pred_wip.png", width = 4.5, height = 3.75)

# Plot: prior predictive comparison
data3 <- data.frame(
log_pm25 = GM$log_pm25,
wip = data2$sim,
vague = data1$sim
)
ggplot(data3, aes(x=log_pm25, y=wip)) +
geom_point(alpha = 0.1) +
geom_point(
aes(y = vague),
color = "red",
alpha = 0.1
) +
xysim_labs
ggsave(filename = "plots/prior_pred_compare.png", width = 4.5, height = 3.75)

# Fit Stan models 1, 2, 3 -------------------------------------------------
# Compile Stan programs
# * simple.stan: simple linear regression (Model 1)
# * hier.stan: non-centered parameterization of hierarchical model (Model 2, Model 3)
simple_mod <- stan_model("stan/simple.stan")
hier_mod <- stan_model("stan/hierarchical.stan")
# Data for model 1
standata1 <- with(GM@data, list(
N = length(log_pm25),
log_pm = log_pm25,
log_sat = log_sat
))
# Data for model 2 (using super-regions from WHO)
standata2 <- with(GM@data, list(
N = length(log_pm25),
R = length(unique(super_region)),
log_pm = log_pm25,
log_sat = log_sat,
region = super_region
))
# Data for model 3 (using super-regions from clustering)
standata3 <- standata2
standata3$R <- length(unique(GM$cluster_region))
standata3$region <- GM$cluster_region
# Fit the models with Stan
nuts_controls <- list(max_treedepth = 15, adapt_delta = 0.99)
mod1 <- sampling(simple_mod, data = standata1, seed = 2402)
SAMPLING FOR MODEL 'simple' NOW (CHAIN 1).
Gradient evaluation took 0.000554 seconds
1000 transitions using 10 leapfrog steps per transition would take 5.54 seconds.
Adjust your expectations accordingly!
Iteration: 1 / 2000 [ 0%] (Warmup)
Iteration: 200 / 2000 [ 10%] (Warmup)
Iteration: 400 / 2000 [ 20%] (Warmup)
Iteration: 600 / 2000 [ 30%] (Warmup)
Iteration: 800 / 2000 [ 40%] (Warmup)
Iteration: 1000 / 2000 [ 50%] (Warmup)
Iteration: 1001 / 2000 [ 50%] (Sampling)
Iteration: 1200 / 2000 [ 60%] (Sampling)
Iteration: 1400 / 2000 [ 70%] (Sampling)
Iteration: 1600 / 2000 [ 80%] (Sampling)
Iteration: 1800 / 2000 [ 90%] (Sampling)
Iteration: 2000 / 2000 [100%] (Sampling)
Elapsed Time: 2.52046 seconds (Warm-up)
2.69208 seconds (Sampling)
5.21255 seconds (Total)
SAMPLING FOR MODEL 'simple' NOW (CHAIN 2).
Gradient evaluation took 0.000181 seconds
1000 transitions using 10 leapfrog steps per transition would take 1.81 seconds.
Adjust your expectations accordingly!
Iteration: 1 / 2000 [ 0%] (Warmup)
Iteration: 200 / 2000 [ 10%] (Warmup)
Iteration: 400 / 2000 [ 20%] (Warmup)
# Graphical posterior predictive checks -----------------------------------
theme_set(bayesplot::theme_default(base_size = 14))
y <- standata2$log_pm
yrep1 <- as.matrix(mod1, pars = "log_pm_rep")
yrep2 <- as.matrix(mod2, pars = "log_pm_rep")
yrep3 <- as.matrix(mod3, pars = "log_pm_rep")
samp100 <- sample(nrow(yrep1), 100)
# overlaid densities
color_scheme_set("blue")
ppc_dens_overlay(y, yrep1[samp100, ]) +
coord_cartesian(ylim = c(0, 0.7), xlim = c(0, 6)) +
legend_none()
ggsave(filename = "plots/ppc_dens1.png", width = 4.5, height = 3.75)

color_scheme_set("gray")
ppc_dens_overlay(y, yrep2[samp100, ]) +
coord_cartesian(ylim = c(0, 0.7), xlim = c(0, 6)) +
legend_none()
ggsave(filename = "plots/ppc_dens2.png", width = 4.5, height = 3.75)

color_scheme_set("red")
ppc_dens_overlay(y, yrep3[samp100, ]) +
coord_cartesian(ylim = c(0, 0.7), xlim = c(0, 6)) +
legend_none()
ggsave(filename = "plots/ppc_dens3.png", width = 4.5, height = 3.75)

# stat: skew
skew <- function(x) {
xdev <- x - mean(x)
n <- length(x)
r <- sum(xdev^3) / sum(xdev^2)^1.5
return(r * sqrt(n) * (1 - 1/n)^1.5)
}
color_scheme_set("blue")
ppc_stat(y, yrep1, stat = "skew", binwidth = 0.01) +
xlim(0, .6) +
legend_none()
ggsave(filename = "plots/ppc_skew1.png", width = 4.5, height = 3.75)

color_scheme_set("gray")
ppc_stat(y, yrep2, stat = "skew", binwidth = 0.01) +
xlim(0, .6) +
legend_none()
ggsave(filename = "plots/ppc_skew2.png", width = 4.5, height = 3.75)

color_scheme_set("red")
ppc_stat(y, yrep3, stat = "skew", binwidth = 0.01) +
xlim(0, .6) +
legend_none()
ggsave(filename = "plots/ppc_skew3.png", width = 4.5, height = 3.75)

# stat: group medians
superregion <- GM@data$super_region_name
superregion <- factor(superregion, levels = levels(superregion)[c(2,1,3:7)])
color_scheme_set("blue")
ppc_stat_grouped(y, yrep1,
group = superregion,
stat = "median",
facet_args = list(nrow = 2)) +
facet_text(size = rel(0.7)) +
scale_x_continuous(breaks = function(x) pretty(x, n = 3)) +
legend_none()
ggsave(filename = "plots/ppc_med_grouped1.png", height = 3, width = 7)

color_scheme_set("gray")
ppc_stat_grouped(y, yrep2,
group = superregion,
stat = "median",
facet_args = list(nrow = 2)) +
facet_text(size = rel(0.7)) +
scale_x_continuous(breaks = function(x) pretty(x, n = 3)) +
legend_none()
ggsave(filename = "plots/ppc_med_grouped2.png", height = 3, width = 7)

color_scheme_set("red")
ppc_stat_grouped(y, yrep3,
group = standata3$region,
stat = "median",
facet_args = list(nrow = 2)) +
facet_text(size = rel(0.7)) +
scale_x_continuous(breaks = function(x) pretty(x, n = 3)) +
legend_none()
ggsave(filename = "plots/ppc_med_grouped3.png", height = 3, width = 7)

LS0tCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyfQpsaWJyYXJ5KHNwKQpsaWJyYXJ5KHNwZGVwKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHJzdGFuKQpsaWJyYXJ5KGxvbykKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGJheWVzcGxvdCkKbGlicmFyeShnbG1uZXQpCnRoZW1lX3NldChiYXllc3Bsb3Q6OnRoZW1lX2RlZmF1bHQoYmFzZV9zaXplID0gMTQpKQoKIyBsb2FkICdHTScgU3BhdGlhbFBvaW50c0RhdGFGcmFtZQpsb2FkKCJiYXllcy12aXMuUkRhdGEiKQpgYGAKCgpgYGB7cn0KR01AZGF0YSA8LSBHTUBkYXRhICU+JSAKICBtdXRhdGUoCiAgICBsb2dfcG0yNSA9IGxvZyhwbTI1KSwgCiAgICBsb2dfc2F0ID0gbG9nKHNhdF8yMDE0KQogICkKYGBgCgoKV2hhdCB2YXJpYWJsZXMgYXJlIGF2YWlsYWJsZSBpbiB0aGlzIGRhdGEgc2V0PwpgYGB7cn0KcHJpbnQoY29sbmFtZXMoR01AZGF0YSkpCmBgYAoKUmVncmVzc2lvbiBvbiB0aGUgb3JpZ2luYWwgdmFsdWVzIGluc3RlYWQgb2YgaW4gbG9nLWRvbWFpbgpgYGB7cn0KeHlsYWJzIDwtIGxhYnMoCiAgeCA9IGV4cHJlc3Npb24oc2F0ZWxsaXRlKSwgCiAgeSA9IGV4cHJlc3Npb24oUE1bMi41XSkKKQpyZWdpb25fY29sb3JfbWFudWFsID0gc2NhbGVfY29sb3JfbWFudWFsKAogICAgdmFsdWVzID0gCiAgICAgIGMoIkUtRXVyL0MtRXVyL0MtQXNpYSIgPSAiIzAwQzA5NCIsCiAgICAgICAgIkhpZ2hJbmNvbWUiID0gIiNGQjYxRDciLAogICAgICAgICJMYXRBbS9DYXJpYiIgPSAiIzUzQjQwMCIsCiAgICAgICAgIk4tQWZyL01pZEVhc3QiID0gIiNBNThBRkYiLAogICAgICAgICJTLUFzaWEiID0gIiMwMEI2RUIiLAogICAgICAgICJTRS1Bc2lhL0UtQXNpYS9PY2VhbmlhIiA9ICIjQzQ5QTAwIiwKICAgICAgICAiU3ViLVNhaGFyYW4gQWZyIiA9ICIjRjg3NjZEIikKICApCgpwbG90MSA8LSBnZ3Bsb3QoR01AZGF0YSwgYWVzKHkgPSBwbTI1LCB4ID0gc2F0XzIwMTQpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBzdXBlcl9yZWdpb25fbmFtZSksIGFscGhhID0gMC40LCBzaXplID0gcmVsKDAuOCkpICsKICByZWdpb25fY29sb3JfbWFudWFsICsKICBnZW9tX3Ntb290aChtZXRob2QgPSBsbSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC41LCBsaW5ldHlwZSA9IDIpICsKICBjb29yZF9lcXVhbCgpICsKICB4eWxhYnMgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZCgKICAgIHRpdGxlID0gTlVMTCwKICAgIG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGEgPSAxLCBzaXplID0gMikKICApKSArCiAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgwLjYpKSkKcGxvdChwbG90MSkKYGBgCgpGaXR0aW5nIGEgc2Vjb25kIGRlZ3JlZSBwb2x5bm9taWFsIGluc3RlYWQKYGBge3J9Cnh5bGFicyA8LSBsYWJzKAogIHggPSBleHByZXNzaW9uKGxvZyhzYXRlbGxpdGUpKSwgCiAgeSA9IGV4cHJlc3Npb24obG9nKFBNWzIuNV0pKQopCnJlZ2lvbl9jb2xvcl9tYW51YWwgPSBzY2FsZV9jb2xvcl9tYW51YWwoCiAgICB2YWx1ZXMgPSAKICAgICAgYygiRS1FdXIvQy1FdXIvQy1Bc2lhIiA9ICIjMDBDMDk0IiwKICAgICAgICAiSGlnaEluY29tZSIgPSAiI0ZCNjFENyIsCiAgICAgICAgIkxhdEFtL0NhcmliIiA9ICIjNTNCNDAwIiwKICAgICAgICAiTi1BZnIvTWlkRWFzdCIgPSAiI0E1OEFGRiIsCiAgICAgICAgIlMtQXNpYSIgPSAiIzAwQjZFQiIsCiAgICAgICAgIlNFLUFzaWEvRS1Bc2lhL09jZWFuaWEiID0gIiNDNDlBMDAiLAogICAgICAgICJTdWItU2FoYXJhbiBBZnIiID0gIiNGODc2NkQiKQogICkKCnBsb3QxIDwtIGdncGxvdChHTUBkYXRhLCBhZXMoeSA9IGxvZ19wbTI1LCB4ID0gbG9nX3NhdCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHN1cGVyX3JlZ2lvbl9uYW1lKSwgYWxwaGEgPSAwLjQsIHNpemUgPSByZWwoMC44KSkgKwogIHJlZ2lvbl9jb2xvcl9tYW51YWwgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9IGdsbSwgZm9ybXVsYT15fnBvbHkoeCwgMiksIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuNSwgbGluZXR5cGUgPSAyKSArCiAgY29vcmRfZXF1YWwoKSArCiAgeHlsYWJzICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQoCiAgICB0aXRsZSA9IE5VTEwsCiAgICBvdmVycmlkZS5hZXMgPSBsaXN0KGFscGhhID0gMSwgc2l6ZSA9IDIpCiAgKSkgKwogIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC42KSkpCnBsb3QocGxvdDEpCmBgYAoKTW9kZWwgdXNlZCBpbiB0aGUgcGFwZXIKYGBge3J9Cnh5bGFicyA8LSBsYWJzKAogIHggPSBleHByZXNzaW9uKGxvZyhzYXRlbGxpdGUpKSwgCiAgeSA9IGV4cHJlc3Npb24obG9nKFBNWzIuNV0pKQopCnJlZ2lvbl9jb2xvcl9tYW51YWwgPSBzY2FsZV9jb2xvcl9tYW51YWwoCiAgICB2YWx1ZXMgPSAKICAgICAgYygiRS1FdXIvQy1FdXIvQy1Bc2lhIiA9ICIjMDBDMDk0IiwKICAgICAgICAiSGlnaEluY29tZSIgPSAiI0ZCNjFENyIsCiAgICAgICAgIkxhdEFtL0NhcmliIiA9ICIjNTNCNDAwIiwKICAgICAgICAiTi1BZnIvTWlkRWFzdCIgPSAiI0E1OEFGRiIsCiAgICAgICAgIlMtQXNpYSIgPSAiIzAwQjZFQiIsCiAgICAgICAgIlNFLUFzaWEvRS1Bc2lhL09jZWFuaWEiID0gIiNDNDlBMDAiLAogICAgICAgICJTdWItU2FoYXJhbiBBZnIiID0gIiNGODc2NkQiKQogICkKCnBsb3QxIDwtIGdncGxvdChHTUBkYXRhLCBhZXMoeSA9IGxvZ19wbTI1LCB4ID0gbG9nX3NhdCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHN1cGVyX3JlZ2lvbl9uYW1lKSwgYWxwaGEgPSAwLjQsIHNpemUgPSByZWwoMC44KSkgKwogIHJlZ2lvbl9jb2xvcl9tYW51YWwgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9IGxtLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjUsIGxpbmV0eXBlID0gMikgKwogIGNvb3JkX2VxdWFsKCkgKwogIHh5bGFicyArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKAogICAgdGl0bGUgPSBOVUxMLAogICAgb3ZlcnJpZGUuYWVzID0gbGlzdChhbHBoYSA9IDEsIHNpemUgPSAyKQogICkpICsKICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuNikpKQpwbG90KHBsb3QxKQpgYGAKCmBgYHtyfQpyMSA8LSBzdWJzZXQoR01AZGF0YSwgc3VwZXJfcmVnaW9uPT0xKQpyMiA8LSBzdWJzZXQoR01AZGF0YSwgc3VwZXJfcmVnaW9uPT0yKQpyMyA8LSBzdWJzZXQoR01AZGF0YSwgc3VwZXJfcmVnaW9uPT0zKQpyNCA8LSBzdWJzZXQoR01AZGF0YSwgc3VwZXJfcmVnaW9uPT00KQpyNSA8LSBzdWJzZXQoR01AZGF0YSwgc3VwZXJfcmVnaW9uPT01KQpyNiA8LSBzdWJzZXQoR01AZGF0YSwgc3VwZXJfcmVnaW9uPT02KQpyNyA8LSBzdWJzZXQoR01AZGF0YSwgc3VwZXJfcmVnaW9uPT03KQpgYGAKCmBgYHtyfQpiMSA8LSBsbShyMSRsb2dfcG0yNSB+IHIxJGxvZ19zYXQpCnByaW50KGIxJGNvZWZmaWNpZW50cykKYjIgPC0gbG0ocjIkbG9nX3BtMjUgfiByMiRsb2dfc2F0KQpwcmludChiMiRjb2VmZmljaWVudHMpCmIzIDwtIGxtKHIzJGxvZ19wbTI1IH4gcjMkbG9nX3NhdCkKcHJpbnQoYjMkY29lZmZpY2llbnRzKQpiNCA8LSBsbShyNCRsb2dfcG0yNSB+IHI0JGxvZ19zYXQpCnByaW50KGI0JGNvZWZmaWNpZW50cykKYjUgPC0gbG0ocjUkbG9nX3BtMjUgfiByNSRsb2dfc2F0KQpwcmludChiNSRjb2VmZmljaWVudHMpCmI2IDwtIGxtKHI2JGxvZ19wbTI1IH4gcjYkbG9nX3NhdCkKcHJpbnQoYjYkY29lZmZpY2llbnRzKQpiNyA8LSBsbShyNyRsb2dfcG0yNSB+IHI3JGxvZ19zYXQpCnByaW50KGI3JGNvZWZmaWNpZW50cykKYGBgCgpgYGB7cn0KcGxvdF9yMSA8LSBnZ3Bsb3QocjMsIGFlcyh5ID0gbG9nX3BtMjUsIHggPSBsb2dfc2F0KSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IHN1cGVyX3JlZ2lvbl9uYW1lKSwgYWxwaGEgPSAwLjIsIHNpemUgPSByZWwoMC43NSkpICsgCiAgcmVnaW9uX2NvbG9yX21hbnVhbCArCiAgZ2VvbV9zbW9vdGgoYWVzKGNvbG91ciA9IHN1cGVyX3JlZ2lvbl9uYW1lKSwgbWV0aG9kID0gbG0pICsgCiAgY29vcmRfZXF1YWwoKSArCiAgeHlsYWJzICsgCiAgbGVnZW5kX25vbmUoKSAKCnBsb3QocGxvdF9yMSkKYGBgCgpTYW1lIHBsb3QgYXMgYWJvdmUgKyBzZXBhcmF0ZSBmaXRzIGZvciBlYWNoIHN1cGVyLXJlZ2lvbgpgYGB7cn0KcGxvdDIgPC0gZ2dwbG90KEdNQGRhdGEsIGFlcyh5ID0gbG9nX3BtMjUsIHggPSBsb2dfc2F0KSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IHN1cGVyX3JlZ2lvbl9uYW1lKSwgYWxwaGEgPSAwLjIsIHNpemUgPSByZWwoMC43NSkpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0sIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuNSwgbGluZXR5cGUgPSAyKSArIAogIHJlZ2lvbl9jb2xvcl9tYW51YWwgKwogIGdlb21fc21vb3RoKGFlcyhjb2xvdXIgPSBzdXBlcl9yZWdpb25fbmFtZSksIG1ldGhvZCA9IGxtKSArIAogIGNvb3JkX2VxdWFsKCkgKwogIHh5bGFicyArIAogIGxlZ2VuZF9ub25lKCkgCgpwbG90KHBsb3QyKQpgYGAKCgpEZXJpdmUgbGFiZWxzIGZyb20gdGhlIGRhdGEgYmFzZWQgb24gYXZlcmFnZSBQTTIuNSBjb25jZW50cmF0aW9uIGluIGVhY2ggY291bnRyeQpgYGB7cn0KYXZlcmFnZSA8LSAKICBHTUBkYXRhICU+JSAKICBncm91cF9ieShpc28zKSAlPiUgCiAgc3VtbWFyaXNlKHBtMjUgPSBtZWFuKHBtMjUpKQpkIDwtIGRpc3QoYXZlcmFnZSkKaGggPC0gaGNsdXN0KGQpCmNsdXN0IDwtIGN1dHJlZShoaCxrID0gNikKR01AZGF0YSRjbHVzdGVyX3JlZ2lvbiA8LQogIHNhcHBseShHTUBkYXRhJGlzbzMsIGZ1bmN0aW9uKHgpIGNsdXN0W3doaWNoKGF2ZXJhZ2UkaXNvMyA9PSB4KV0pCgpwcmludCh0YWJsZShHTUBkYXRhJGNsdXN0ZXJfcmVnaW9uKSkKCmNsdXN0ZXJfY29sb3JfbWFudWFsID0gc2NhbGVfY29sb3JfbWFudWFsKAogICAgdmFsdWVzID0gCiAgICAgIGMoIjQiID0gIiMwMEMwOTQiLAogICAgICAgICIxIiA9ICIjRkI2MUQ3IiwgCiAgICAgICAgIjUiID0gIiM1M0I0MDAiLAogICAgICAgICIyIiA9ICIjQTU4QUZGIiwKICAgICAgICAiMyIgPSAiIzAwQjZFQiIsCiAgICAgICAgIjYiID0gIiNDNDlBMDAiLAogICAgICAgICI3IiA9ICIjRjg3NjZEIikKICApCmBgYAoKCmBgYHtyfQpwbG90MyA8LQogIGdncGxvdChHTUBkYXRhLCBhZXMoCiAgICB5ID0gbG9nX3BtMjUsCiAgICB4ID0gbG9nX3NhdAogICkpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gYXMuZmFjdG9yKGNsdXN0ZXJfcmVnaW9uKSksIGFscGhhID0gMC4yLCBzaXplID0gcmVsKDAuNzUpKSArIAogIGNsdXN0ZXJfY29sb3JfbWFudWFsICsKICBnZW9tX3Ntb290aCgKICAgIG1ldGhvZCA9IGxtLCAKICAgIGNvbG9yID0gImJsYWNrIiwgCiAgICBzaXplID0gMC41LCAKICAgIGxpbmV0eXBlID0gMgogICkgKyAKICBnZW9tX3Ntb290aChhZXMoY29sb3VyID0gYXMuZmFjdG9yKGNsdXN0ZXJfcmVnaW9uKSksIG1ldGhvZCA9IGxtKSArIAogIGNvb3JkX2VxdWFsKCkgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZCgKICAgIHRpdGxlID0gTlVMTCwKICAgIG92ZXJyaWRlLmFlcyA9IGxpc3QoYWxwaGEgPSAxLCBzaXplID0gMikKICApKSArCiAgeHlsYWJzCgpwbG90KHBsb3QzKQpgYGAKCmBgYHtyfQojIFByaW9yIHByZWRpY3RpdmUgc2ltdWxhdGlvbnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgSW52ZXJzZSBHYW1tZSBkaXN0cmlidXRpb24uIApsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShncmlkKQpsaWJyYXJ5KGludmdhbW1hKQpsaWJyYXJ5KGdncGxvdDIpOyB0aGVtZV9zZXQodGhlbWVfYncoKSkKeCA8LSBzZXEoMCwgNTAwLCAuMDEpCnFwbG90KHgsIGRpbnZnYW1tYSh4LCAxLCAxKSwgZ2VvbSA9ICJsaW5lIikgLT4gcGxvdDEKcXBsb3QoeCwgZGludmdhbW1hKHgsIDEsIDEwMCksIGdlb20gPSAibGluZSIpIC0+IHBsb3QyCiNxcGxvdCh4LCAxL2RpbnZnYW1tYSh4LCAxLCAxKSwgZ2VvbSA9ICJsaW5lIikgLT4gcGxvdDMKI3FwbG90KHgsIDEvZGludmdhbW1hKHgsIDEsIDEwMCksIGdlb20gPSAibGluZSIpIC0+IHBsb3Q0CiNxcGxvdCh4LCBkaW52Z2FtbWEoeCwgMiwgMTAwKSwgZ2VvbSA9ICJsaW5lIikgLT4gcGxvdDMKI3FwbG90KHgsIGRpbnZnYW1tYSh4LCA0LCAxMDApLCBnZW9tID0gImxpbmUiKSAtPiBwbG90NAoKZ3JpZC5hcnJhbmdlKHBsb3QxLCBwbG90MiwgbmNvbCA9IDIpCmBgYApgYGB7cn0KIyBQbG90OiBwcmlvciBwcmVkaWN0aXZlIHdpdGggdmFndWUgcHJpb3JzCnNldC5zZWVkKHNlZWQgPSAxOTIzODQwNDgzKQoKdGF1MCA8LSAxIC8gc3FydChyZ2FtbWEoMSwgMSwgcmF0ZSA9IDEwMCkpCnRhdTEgPC0gMSAvIHNxcnQocmdhbW1hKDEsIDEsIHJhdGUgPSAxMDApKQpzaWdtYSA8LSAxIC8gc3FydChyZ2FtbWEoMSwgMSwgcmF0ZSA9IDEwMCkpCmJldGEwaSA8LSBybm9ybSg4LCAwLCB0YXUwKQpiZXRhMWkgPC0gcm5vcm0oOCwgMCwgdGF1MSkKYmV0YTAgPC0gcm5vcm0oMSwgMCwgMTAwKQpiZXRhMSA8LSBybm9ybSgxLCAwLCAxMDApCgpOc2ltIDwtIGxlbmd0aChHTUBkYXRhJHN1cGVyX3JlZ2lvbikKeHlzaW1fbGFicyA8LSBsYWJzKAogIHggPSBleHByZXNzaW9uKHBhc3RlKCJPYnNlcnZlZCAiLCBsb2coUE1bMi41XSkpKSwKICB5ID0gIlNpbXVsYXRlZCBkYXRhIChsb2cgc2NhbGUpIgopCgpkYXRhMSA8LSBkYXRhLmZyYW1lKAogIGxvZ19wbTI1ID0gR00kbG9nX3BtMjUsCiAgc2ltID0gYmV0YTAgKyBiZXRhMGlbR00kc3VwZXJfcmVnaW9uXSArCiAgICAoYmV0YTEgKyBiZXRhMWlbR00kc3VwZXJfcmVnaW9uXSkgKiBHTSRsb2dfc2F0ICsKICAgIHJub3JtKE5zaW0sIG1lYW4gPSAwLCBzZCA9IHNpZ21hKQopCgp0aGVtZV9zZXQoYmF5ZXNwbG90Ojp0aGVtZV9kZWZhdWx0KGJhc2Vfc2l6ZSA9IDE4KSkKdGhlbWVfdXBkYXRlKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApKQoKZ2dwbG90KGRhdGExLCBhZXMoeCA9IGxvZ19wbTI1LCB5ID0gc2ltKSkgKyAKICBnZW9tX3BvaW50KGFscGhhID0gMC4xLCBjb2xvciA9ICJyZWQiKSArIAogIHh5c2ltX2xhYnMgKyBnZ3RpdGxlKCJWYWd1ZSBSZWNvbW1lbmRlZCBQcmlvcnMiKQpnZ3NhdmUoZmlsZW5hbWUgPSAicGxvdHMvcHJpb3JfcHJlZF92YWd1ZS5wbmciLCB3aWR0aCA9IDQuNSwgaGVpZ2h0ID0gMy43NSkKYGBgCgpgYGB7cn0KIyBQbG90OiBwcmlvciBwcmVkaWN0aXZlIHdpdGggd2Vha2x5IGluZm9ybWF0aXZlIHByaW9ycwpzZXQuc2VlZChzZWVkID0gMTkyMzg0MDQ3OSkKdGF1MCA8LSBhYnMocm5vcm0oMSwgMCwgMSkpCnRhdTEgPC0gYWJzKHJub3JtKDEsIDAsIDEpKQpzaWdtYSA8LSBhYnMocm5vcm0oMSwgMCwgMSkpCmJldGEwaSA8LSBybm9ybSg4LCAwLCB0YXUwKQpiZXRhMWkgPC0gcm5vcm0oOCwgMCwgdGF1MSkKYmV0YTAgPC0gcm5vcm0oMSwgMCwgMSkKYmV0YTEgPC0gcm5vcm0oMSwgMSwgMSkKCmRhdGEyIDwtIGRhdGEuZnJhbWUoCiAgbG9nX3BtMjUgPSBHTSRsb2dfcG0yNSwKICBzaW0gPSBiZXRhMCArIGJldGEwaVtHTSRzdXBlcl9yZWdpb25dICsKICAgIChiZXRhMSArIGJldGExaVtHTSRzdXBlcl9yZWdpb25dKSAqIEdNJGxvZ19zYXQgKwogICAgcm5vcm0oTnNpbSwgbWVhbiA9IDAsIHNkID0gc2lnbWEpCikKCmdncGxvdChkYXRhMiwgYWVzKHggPSBsb2dfcG0yNSwgeSA9IHNpbSkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC4xKSArIAogIHh5c2ltX2xhYnMgKyBnZ3RpdGxlKCJXZWFrbHkgaW5mb3JtYXRpdmUgam9pbnQgcHJpb3IgZGF0YSBnZW5lcmF0aW5nIHByb2Nlc3MiKQpnZ3NhdmUoZmlsZW5hbWUgPSAicGxvdHMvcHJpb3JfcHJlZF93aXAucG5nIiwgd2lkdGggPSA0LjUsIGhlaWdodCA9IDMuNzUpCmBgYAoKYGBge3J9CiMgUGxvdDogcHJpb3IgcHJlZGljdGl2ZSB3aXRoIHdlYWtseSBpbmZvcm1hdGl2ZSBwcmlvcnMgKG5vIHNlZWQpCnRhdTAgPC0gYWJzKHJub3JtKDEsIDAsIDEpKQp0YXUxIDwtIGFicyhybm9ybSgxLCAwLCAxKSkKc2lnbWEgPC0gYWJzKHJub3JtKDEsIDAsIDEpKQpiZXRhMGkgPC0gcm5vcm0oOCwgMCwgdGF1MCkKYmV0YTFpIDwtIHJub3JtKDgsIDAsIHRhdTEpCmJldGEwIDwtIHJub3JtKDEsIDAsIDEpCmJldGExIDwtIHJub3JtKDEsIDEsIDEpCgpkYXRhMiA8LSBkYXRhLmZyYW1lKAogIGxvZ19wbTI1ID0gR00kbG9nX3BtMjUsCiAgc2ltID0gYmV0YTAgKyBiZXRhMGlbR00kc3VwZXJfcmVnaW9uXSArCiAgICAoYmV0YTEgKyBiZXRhMWlbR00kc3VwZXJfcmVnaW9uXSkgKiBHTSRsb2dfc2F0ICsKICAgIHJub3JtKE5zaW0sIG1lYW4gPSAwLCBzZCA9IHNpZ21hKQopCgpnZ3Bsb3QoZGF0YTIsIGFlcyh4ID0gbG9nX3BtMjUsIHkgPSBzaW0pKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMSkgKyAKICB4eXNpbV9sYWJzCmdnc2F2ZShmaWxlbmFtZSA9ICJwbG90cy9wcmlvcl9wcmVkX3dpcC5wbmciLCB3aWR0aCA9IDQuNSwgaGVpZ2h0ID0gMy43NSkKYGBgCgoKYGBge3J9CiMgUGxvdDogcHJpb3IgcHJlZGljdGl2ZSBjb21wYXJpc29uCmRhdGEzIDwtIGRhdGEuZnJhbWUoCiAgbG9nX3BtMjUgPSBHTSRsb2dfcG0yNSwgCiAgd2lwID0gZGF0YTIkc2ltLCAKICB2YWd1ZSA9IGRhdGExJHNpbQopCmdncGxvdChkYXRhMywgYWVzKHg9bG9nX3BtMjUsIHk9d2lwKSkgKyAKICBnZW9tX3BvaW50KGFscGhhID0gMC4xKSArIAogIGdlb21fcG9pbnQoCiAgICBhZXMoeSA9IHZhZ3VlKSwgCiAgICBjb2xvciA9ICJyZWQiLCAKICAgIGFscGhhID0gMC4xCiAgKSArIAogIHh5c2ltX2xhYnMKZ2dzYXZlKGZpbGVuYW1lID0gInBsb3RzL3ByaW9yX3ByZWRfY29tcGFyZS5wbmciLCB3aWR0aCA9IDQuNSwgaGVpZ2h0ID0gMy43NSkKYGBgCgpgYGB7cn0KIyBGaXQgU3RhbiBtb2RlbHMgMSwgMiwgMyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIENvbXBpbGUgU3RhbiBwcm9ncmFtcwojICogc2ltcGxlLnN0YW46IHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiAoTW9kZWwgMSkKIyAqIGhpZXIuc3Rhbjogbm9uLWNlbnRlcmVkIHBhcmFtZXRlcml6YXRpb24gb2YgaGllcmFyY2hpY2FsIG1vZGVsIChNb2RlbCAyLCBNb2RlbCAzKQpzaW1wbGVfbW9kIDwtIHN0YW5fbW9kZWwoInN0YW4vc2ltcGxlLnN0YW4iKQpoaWVyX21vZCA8LSBzdGFuX21vZGVsKCJzdGFuL2hpZXJhcmNoaWNhbC5zdGFuIikKCiMgRGF0YSBmb3IgbW9kZWwgMQpzdGFuZGF0YTEgPC0gd2l0aChHTUBkYXRhLCBsaXN0KAogIE4gPSBsZW5ndGgobG9nX3BtMjUpLAogIGxvZ19wbSA9IGxvZ19wbTI1LAogIGxvZ19zYXQgPSBsb2dfc2F0CikpCgojIERhdGEgZm9yIG1vZGVsIDIgKHVzaW5nIHN1cGVyLXJlZ2lvbnMgZnJvbSBXSE8pCnN0YW5kYXRhMiA8LSB3aXRoKEdNQGRhdGEsIGxpc3QoCiAgTiA9IGxlbmd0aChsb2dfcG0yNSksCiAgUiA9IGxlbmd0aCh1bmlxdWUoc3VwZXJfcmVnaW9uKSksCiAgbG9nX3BtID0gbG9nX3BtMjUsCiAgbG9nX3NhdCA9IGxvZ19zYXQsCiAgcmVnaW9uID0gc3VwZXJfcmVnaW9uCikpCgojIERhdGEgZm9yIG1vZGVsIDMgKHVzaW5nIHN1cGVyLXJlZ2lvbnMgZnJvbSBjbHVzdGVyaW5nKQpzdGFuZGF0YTMgPC0gc3RhbmRhdGEyCnN0YW5kYXRhMyRSIDwtIGxlbmd0aCh1bmlxdWUoR00kY2x1c3Rlcl9yZWdpb24pKQpzdGFuZGF0YTMkcmVnaW9uIDwtIEdNJGNsdXN0ZXJfcmVnaW9uCgojIEZpdCB0aGUgbW9kZWxzIHdpdGggU3RhbgpudXRzX2NvbnRyb2xzIDwtIGxpc3QobWF4X3RyZWVkZXB0aCA9IDE1LCBhZGFwdF9kZWx0YSA9IDAuOTkpCm1vZDEgPC0gc2FtcGxpbmcoc2ltcGxlX21vZCwgZGF0YSA9IHN0YW5kYXRhMSwgc2VlZCA9IDI0MDIpCm1vZDIgPC0gc2FtcGxpbmcoaGllcl9tb2QsIGRhdGEgPSBzdGFuZGF0YTIsIGNvbnRyb2wgPSBudXRzX2NvbnRyb2xzLCBzZWVkID0gMjQwMikKbW9kM19kaXZlcmdlIDwtIHNhbXBsaW5nKGhpZXJfbW9kLCBkYXRhID0gc3RhbmRhdGEzLCBjb250cm9sID0gbnV0c19jb250cm9sc1sxXSwgc2VlZCA9IDI0MDIpCm1vZDMgPC0gc2FtcGxpbmcoaGllcl9tb2QsIGRhdGEgPSBzdGFuZGF0YTMsIGNvbnRyb2wgPSBudXRzX2NvbnRyb2xzLCBzZWVkID0gMjQwMikKCnNhdmUoZmlsZSA9ICJzdGFuL3N0YW5maXRzLlJEYXRhIiwgbW9kMSwgbW9kMiwgbW9kMywgbW9kM19kaXZlcmdlKQoKIyBFeHRyYWN0IHBhcmFtZXRlciBlc3RpbWF0ZXMsIHBvaW50d2lzZSBsb2ctbGlrLCBhbmQgcG9zdGVyaW9yIHByZWRpY3RpdmUgZHJhd3MKa2VlcF9wYXJzIDwtIGMoInNpZ21hIiwgImJldGEwIiwgImJldGExIiwgImJldGEwX3JlZ2lvbiIsICJiZXRhMV9yZWdpb24iLCAidGF1MCIsICJ0YXUxIikKcG9zdGVyaW9yMSA8LSBhcy5hcnJheShtb2QxLCBwYXJzID0ga2VlcF9wYXJzWzE6M10pCnBvc3RlcmlvcjIgPC0gYXMuYXJyYXkobW9kMiwgcGFycyA9IGtlZXBfcGFycykKcG9zdGVyaW9yM19kaXZlcmdlIDwtIGFzLmFycmF5KG1vZDNfZGl2ZXJnZSwgcGFycyA9IGtlZXBfcGFycykKcG9zdGVyaW9yMyA8LSBhcy5hcnJheShtb2QzLCBwYXJzID0ga2VlcF9wYXJzKQpgYGAKCmBgYHtyfQojIEdyYXBoaWNhbCBwb3N0ZXJpb3IgcHJlZGljdGl2ZSBjaGVja3MgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KdGhlbWVfc2V0KGJheWVzcGxvdDo6dGhlbWVfZGVmYXVsdChiYXNlX3NpemUgPSAxNCkpCnkgPC0gc3RhbmRhdGEyJGxvZ19wbQp5cmVwMSA8LSBhcy5tYXRyaXgobW9kMSwgcGFycyA9ICJsb2dfcG1fcmVwIikKeXJlcDIgPC0gYXMubWF0cml4KG1vZDIsIHBhcnMgPSAibG9nX3BtX3JlcCIpCnlyZXAzIDwtIGFzLm1hdHJpeChtb2QzLCBwYXJzID0gImxvZ19wbV9yZXAiKQoKc2FtcDEwMCA8LSBzYW1wbGUobnJvdyh5cmVwMSksIDEwMCkKCiMgb3ZlcmxhaWQgZGVuc2l0aWVzCmNvbG9yX3NjaGVtZV9zZXQoImJsdWUiKQpwcGNfZGVuc19vdmVybGF5KHksIHlyZXAxW3NhbXAxMDAsIF0pICsgCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsIDAuNyksIHhsaW0gPSBjKDAsIDYpKSArCiAgbGVnZW5kX25vbmUoKQpnZ3NhdmUoZmlsZW5hbWUgPSAicGxvdHMvcHBjX2RlbnMxLnBuZyIsIHdpZHRoID0gNC41LCBoZWlnaHQgPSAzLjc1KQoKY29sb3Jfc2NoZW1lX3NldCgiZ3JheSIpCnBwY19kZW5zX292ZXJsYXkoeSwgeXJlcDJbc2FtcDEwMCwgXSkgKyAKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgMC43KSwgeGxpbSA9IGMoMCwgNikpICsKICBsZWdlbmRfbm9uZSgpCmdnc2F2ZShmaWxlbmFtZSA9ICJwbG90cy9wcGNfZGVuczIucG5nIiwgd2lkdGggPSA0LjUsIGhlaWdodCA9IDMuNzUpCgpjb2xvcl9zY2hlbWVfc2V0KCJyZWQiKQpwcGNfZGVuc19vdmVybGF5KHksIHlyZXAzW3NhbXAxMDAsIF0pICsgCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsIDAuNyksIHhsaW0gPSBjKDAsIDYpKSArCiAgbGVnZW5kX25vbmUoKQpnZ3NhdmUoZmlsZW5hbWUgPSAicGxvdHMvcHBjX2RlbnMzLnBuZyIsIHdpZHRoID0gNC41LCBoZWlnaHQgPSAzLjc1KQpgYGAKCmBgYHtyfQojIHN0YXQ6IHNrZXcgCnNrZXcgPC0gZnVuY3Rpb24oeCkgewogIHhkZXYgPC0geCAtIG1lYW4oeCkKICBuIDwtIGxlbmd0aCh4KQogIHIgPC0gc3VtKHhkZXZeMykgLyBzdW0oeGRldl4yKV4xLjUKICByZXR1cm4ociAqIHNxcnQobikgKiAoMSAtIDEvbileMS41KQp9Cgpjb2xvcl9zY2hlbWVfc2V0KCJibHVlIikKcHBjX3N0YXQoeSwgeXJlcDEsIHN0YXQgPSAic2tldyIsIGJpbndpZHRoID0gMC4wMSkgKyAKICB4bGltKDAsIC42KSArIAogIGxlZ2VuZF9ub25lKCkKZ2dzYXZlKGZpbGVuYW1lID0gInBsb3RzL3BwY19za2V3MS5wbmciLCB3aWR0aCA9IDQuNSwgaGVpZ2h0ID0gMy43NSkKCmNvbG9yX3NjaGVtZV9zZXQoImdyYXkiKQpwcGNfc3RhdCh5LCB5cmVwMiwgc3RhdCA9ICJza2V3IiwgYmlud2lkdGggPSAwLjAxKSArIAogIHhsaW0oMCwgLjYpICsgCiAgbGVnZW5kX25vbmUoKQpnZ3NhdmUoZmlsZW5hbWUgPSAicGxvdHMvcHBjX3NrZXcyLnBuZyIsIHdpZHRoID0gNC41LCBoZWlnaHQgPSAzLjc1KQoKY29sb3Jfc2NoZW1lX3NldCgicmVkIikKcHBjX3N0YXQoeSwgeXJlcDMsIHN0YXQgPSAic2tldyIsIGJpbndpZHRoID0gMC4wMSkgKyAKICB4bGltKDAsIC42KSArIAogIGxlZ2VuZF9ub25lKCkKZ2dzYXZlKGZpbGVuYW1lID0gInBsb3RzL3BwY19za2V3My5wbmciLCB3aWR0aCA9IDQuNSwgaGVpZ2h0ID0gMy43NSkKYGBgCgpgYGB7cn0KIyBzdGF0OiBncm91cCBtZWRpYW5zCnN1cGVycmVnaW9uIDwtIEdNQGRhdGEkc3VwZXJfcmVnaW9uX25hbWUKc3VwZXJyZWdpb24gPC0gZmFjdG9yKHN1cGVycmVnaW9uLCBsZXZlbHMgPSBsZXZlbHMoc3VwZXJyZWdpb24pW2MoMiwxLDM6NyldKQoKY29sb3Jfc2NoZW1lX3NldCgiYmx1ZSIpCnBwY19zdGF0X2dyb3VwZWQoeSwgeXJlcDEsIAogICAgICAgICAgICAgICAgIGdyb3VwID0gc3VwZXJyZWdpb24sIAogICAgICAgICAgICAgICAgIHN0YXQgPSAibWVkaWFuIiwgCiAgICAgICAgICAgICAgICAgZmFjZXRfYXJncyA9IGxpc3QobnJvdyA9IDIpKSArIAogIGZhY2V0X3RleHQoc2l6ZSA9IHJlbCgwLjcpKSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBmdW5jdGlvbih4KSBwcmV0dHkoeCwgbiA9IDMpKSArCiAgbGVnZW5kX25vbmUoKQpnZ3NhdmUoZmlsZW5hbWUgPSAicGxvdHMvcHBjX21lZF9ncm91cGVkMS5wbmciLCBoZWlnaHQgPSAzLCB3aWR0aCA9IDcpCgpjb2xvcl9zY2hlbWVfc2V0KCJncmF5IikKcHBjX3N0YXRfZ3JvdXBlZCh5LCB5cmVwMiwgCiAgICAgICAgICAgICAgICAgZ3JvdXAgPSBzdXBlcnJlZ2lvbiwgCiAgICAgICAgICAgICAgICAgc3RhdCA9ICJtZWRpYW4iLAogICAgICAgICAgICAgICAgIGZhY2V0X2FyZ3MgPSBsaXN0KG5yb3cgPSAyKSkgKwogIGZhY2V0X3RleHQoc2l6ZSA9IHJlbCgwLjcpKSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBmdW5jdGlvbih4KSBwcmV0dHkoeCwgbiA9IDMpKSArCiAgbGVnZW5kX25vbmUoKQpnZ3NhdmUoZmlsZW5hbWUgPSAicGxvdHMvcHBjX21lZF9ncm91cGVkMi5wbmciLCBoZWlnaHQgPSAzLCB3aWR0aCA9IDcpCgpjb2xvcl9zY2hlbWVfc2V0KCJyZWQiKQpwcGNfc3RhdF9ncm91cGVkKHksIHlyZXAzLCAKICAgICAgICAgICAgICAgICBncm91cCA9IHN0YW5kYXRhMyRyZWdpb24sCiAgICAgICAgICAgICAgICAgc3RhdCA9ICJtZWRpYW4iLCAKICAgICAgICAgICAgICAgICBmYWNldF9hcmdzID0gbGlzdChucm93ID0gMikpICsgCiAgZmFjZXRfdGV4dChzaXplID0gcmVsKDAuNykpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGZ1bmN0aW9uKHgpIHByZXR0eSh4LCBuID0gMykpICsKICBsZWdlbmRfbm9uZSgpCmdnc2F2ZShmaWxlbmFtZSA9ICJwbG90cy9wcGNfbWVkX2dyb3VwZWQzLnBuZyIsIGhlaWdodCA9IDMsIHdpZHRoID0gNykKYGBgCgo=